﻿namespace MapleRock.P2PEmulator.Core.Events
{
  using System;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.IO;
  using System.Linq;
  using System.Text;
  using System.Xml.Serialization;

  public enum EventType
  {
    Invalid = 0,
    TranslationEvent = 1,
    Broadcast = 2,
  }

  public abstract class BaseEvent
  {
    public BaseEvent(EventType type, uint timestamp)
    {
      Debug.Assert(EventType.Invalid != type, "EventType.Invalid != type");

      this.Type = type;
      this.Timestamp = timestamp;
    }

    public EventType Type { get; private set; }

    public uint Timestamp { get; private set; }

    public static BaseEvent Create(EventType type)
    {
      if (EventType.Invalid == type)
      {
        throw new ArgumentException("[EVENTS]: Event type must be not Invalid.", "type");
      }

      switch (type)
      {
        case EventType.Broadcast: return new BroadcastEvent(uint.MaxValue, uint.MaxValue, uint.MaxValue);

        case EventType.TranslationEvent: return new TranslationEvent(
          uint.MaxValue,
          uint.MaxValue,
          TranslationAgentType.Invalid,
          uint.MaxValue,
          TranslationAgentType.Invalid,
          TranslationStatus.Invalid);

        default:
          var errorMessage = string.Format("[EVENTS]: Unexpected type [{0}]", type);
          throw new InvalidOperationException(errorMessage);
      }
    }

    public virtual void Serialize(BinaryWriter output)
    {
      if (null == output)
      {
        throw new ArgumentNullException("output");
      }

      Debug.Assert(EventType.Invalid != this.Type, "XmlEventType.Invalid != this.Type");
      output.Write(Convert.ToByte(this.Type));

      Debug.Assert(uint.MaxValue != this.Timestamp, "uint.MaxValue != this.Timestamp");
      output.Write(Convert.ToUInt32(this.Timestamp));
    }

    public virtual void Deserialize(BinaryReader input)
    {
      var typeCode = input.ReadByte();
      if (this.Type != (EventType)typeCode)
      {
        var errorMessage = string.Format(
          "[EVENTS]: Unexpected typecode [{0}], expected [{1} {2}]",
          typeCode,
          this.Type,
          (int)this.Type);
        throw new FormatException(errorMessage);
      }

      this.Timestamp = input.ReadUInt32();
    }
  }
}
